use std::fs;
use anyhow::{Context, Result};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MemInfo {
    pub size: u64,
    pub resident: u64,
    pub shared: u64,
    pub trs: u64,
    pub lrs: u64,
    pub drs: u64,
    pub dt: u64,
}

type RawData = (u64, u64, u64, u64, u64, u64, u64);
#[inline]
fn read_statm(pid: u64) -> Result<RawData> {
    let res = fs::read_to_string(format!("/proc/{}/statm", pid))
        .with_context( || format!("Failed to read /proc/{}/statm", pid))?;
    let mut iter = res.split_whitespace();
    let data: RawData = 
        (iter.next().unwrap().parse()?,
        iter.next().unwrap().parse()?,
        iter.next().unwrap().parse()?,
        iter.next().unwrap().parse()?,
        iter.next().unwrap().parse()?,
        iter.next().unwrap().parse()?,
        iter.next().unwrap().parse()?);
    Ok(data)
}


impl MemInfo {
    pub fn new(pid: u64, pagesize: u64) -> Result<Self> {
        let (size, resident, shared, trs, lrs, drs, dt) = read_statm(pid)?;
        Ok(Self {
            size: size * pagesize,
            resident: resident * pagesize,
            shared: shared * pagesize,
            trs: trs * pagesize,
            lrs: lrs * pagesize,
            drs: drs * pagesize,
            dt: dt * pagesize,
        })
    }
}

mod test {
    use super::*;
    #[test]
    fn test_read_statm() {
        let data = read_statm(1).unwrap();
        println!("{:?}", data);
    }
    #[test]
    fn test_meminfo() {
        let data = MemInfo::new(1, 4096).unwrap();
        println!("{:?}", data);
    }
}